﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using TaiwuModFramework.Common.Abstract;
using TaiwuModFramework.Common.Attribute;
using TaiwuModFramework.Common.Base;
using TaiwuModFramework.Common.Info;

namespace TaiwuModFramework.Common.Manager {
    public class ServiceManager {

        private static readonly ServiceManager instance = new ServiceManager();
        private static readonly Dictionary<string, Dictionary<string, ServiceInfo>> Services = new Dictionary<string, Dictionary<string, ServiceInfo>>();
        private static ALogger Log { get {return AFwDomain.Log; } }
        public static ServiceManager GetInstance() {
            return instance;
        }

        /// <summary>
        /// 添加服务
        /// </summary>
        /// <param name="modIdStr">modId</param>
        /// <param name="serviceObj">组件实例</param>
        public static void AddServices(string modIdStr, AService serviceObj) {
            if(serviceObj == null) return;
            Dictionary<string, ServiceInfo> services;
            if(Services.ContainsKey(modIdStr)) {
                services = Services[modIdStr];
            } else {
                services = new Dictionary<string, ServiceInfo>();
                Services.Add(modIdStr, services);
            }
            // 获取所有标注有AttrService的方法
            foreach(var method in serviceObj.GetType().GetMethods(AttrService.Flag)) {
                var attr = method.GetCustomAttribute<AttrService>();
                if(attr == null) continue;
                var key = CalcServiceKey(modIdStr, attr, method);
                if(!services.ContainsKey(key)) {
                    services.Add(key, new ServiceInfo(modIdStr, attr.ServiceName, method, serviceObj));
                }
            }

        }

        public static void AddServices(string modIdStr, IEnumerable<AService> services) {
            if(services == null) return;
            foreach(var serviceObj in services) {
                AddServices(modIdStr, serviceObj);
            }
        }


        public static object CallService(string modIdStr, string serviceName, Type[] argTypes, object[] args) {
            return CallService(modIdStr, serviceName, argTypes.Select(t => t == null ? "Null" : t.FullName).ToArray(), args);
            
        }
        public static object CallService(string modIdStr, string serviceName, string[] argTypeNames, object[] args) {
            string key = CalcServcieKey(modIdStr, serviceName, argTypeNames);
            Log.Info($"调用服务:{key}");
            if(Services.ContainsKey(modIdStr) && Services[modIdStr].ContainsKey(key)) {
                return Services[modIdStr][key].Invoke(args);
            } else {
                throw new Exception(String.Format("服务[{0}]不存在，请检查服务名称与参数列表", key));
            }
        }

        public static string CalcServiceKey(string modIdStr, AttrService service, MethodInfo method) {
            Type[] types = null;
            if(method != null) {
                types = method.GetParameters().Select(pi => pi.ParameterType).ToArray();
            }
            return CalcServiceKey(modIdStr, service.ServiceName, types);
        }

        public static string CalcServiceKey(string modIdStr, string serviceName, Type[] types) {
            return CalcServcieKey(modIdStr, serviceName, types.Select(t => t == null ? "Null" : t.FullName).ToArray());
        }

        public static string CalcServcieKey(string modIdStr, string serviceName, string[] argTypeNames) {
            return String.Format("Service/{0}/{1}({2})", modIdStr, serviceName, string.Join(",", argTypeNames));
        }



        public static List<string> GetServiceList() {
            List<string> list = new List<string>();
            foreach(string modIdStr in Services.Keys) {
                list.AddRange(Services[modIdStr].Select(kv => kv.Key));
            }
            return list;
        }

        public static List<string> GetServiceList(string modIdStr) {
            List<string> list = new List<string>();
            if(Services.ContainsKey(modIdStr)) {
                list.AddRange(Services[modIdStr].Select(kv => kv.Key));
            }
            return list;
        }
    }
}

